use once_cell::sync::Lazy;
use sqlx::{SqlitePool, Row};
use std::sync::Arc;
use tokio::sync::RwLock;

/// 全局数据库连接池（单例）
///
/// 使用 `once_cell::sync::Lazy` 与 `tokio::sync::RwLock` 实现全局异步安全的数据库连接。
/// - `Arc`：实现多线程共享。
/// - `RwLock<Option<SqlitePool>>`：允许异步读写，且在初始化前为 `None`。
///
/// 该对象在程序生命周期内只初始化一次。
static DB_POOL: Lazy<Arc<RwLock<Option<SqlitePool>>>> =
    Lazy::new(|| Arc::new(RwLock::new(None)));

/// 初始化数据库（仅执行一次）
///
/// 创建 SQLite 数据库连接池并初始化表结构。
/// 数据库文件位于程序根目录下的 `vxPath.db`。
///
/// ### 执行逻辑
/// 1. 创建数据库连接池。
/// 2. 将连接池存入全局变量 [`DB_POOL`]。
/// 3. 调用 [`create_table`] 创建 `vxPath` 表。
///
/// ### 错误处理
/// - 如果数据库连接失败，程序将直接 `panic`。
///
/// ### 示例
/// ```rust
/// // 程序启动时初始化数据库
/// init_db().await;
/// ```
pub async fn init_db() {
    let pool = SqlitePool::connect("sqlite://vxPath.db")
        .await
        .expect("数据库连接失败");

    {
        let mut global = DB_POOL.write().await;
        *global = Some(pool.clone());
    }

    create_table(&pool).await;
}

/// 创建 `vxPath` 表（仅在不存在时创建）
///
/// 该表用于存储微信可执行文件路径，仅保存一条记录。
/// 表结构如下：
///
/// | 字段名 | 类型 | 说明 |
/// |--------|------|------|
/// | id | INTEGER | 主键，自增 |
/// | path | TEXT | 微信可执行文件路径 |
///
/// ### 参数
/// - `pool`: SQLite 连接池实例。
///
/// ### 注意
/// - 该函数不会返回错误，只会忽略执行失败的情况（通过 `.ok()`）。
async fn create_table(pool: &SqlitePool) {
    sqlx::query(
        "CREATE TABLE IF NOT EXISTS vxPath (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            path TEXT
        )",
    )
        .execute(pool)
        .await
        .ok();
}

/// 获取数据库连接池（确保已初始化）
///
/// 从全局 [`DB_POOL`] 中读取数据库连接实例。
///
/// ### 返回值
/// 返回一个 [`SqlitePool`] 实例，用于执行数据库操作。
///
/// ### 注意事项
/// - 若数据库尚未初始化，将触发 `panic!("数据库未初始化")`。
async fn get_pool() -> SqlitePool {
    let pool_guard = DB_POOL.read().await;
    pool_guard.as_ref().expect("数据库未初始化").clone()
}

/// 从数据库读取微信可执行文件路径
///
/// 该函数查询 `vxPath` 表的第一条记录，并返回微信可执行文件路径。
///
/// ### 返回值
/// - `Some(String)`：查询到路径。
/// - `None`：数据库为空或读取失败。
///
/// ### 示例
/// ```rust
/// if let Some(path) = get_wechat_path_from_db().await {
///     println!("当前微信路径: {}", path);
/// } else {
///     println!("尚未设置微信路径");
/// }
/// ```
pub async fn get_wechat_path_from_db() -> Option<String> {
    let pool = get_pool().await;

    if let Ok(row) = sqlx::query("SELECT path FROM vxPath LIMIT 1")
        .fetch_one(&pool)
        .await
    {
        return row.try_get::<String, _>("path").ok();
    }
    None
}

/// 保存或更新微信路径（保持仅一条记录）
///
/// 若表中已存在路径，则执行更新；否则插入新路径。
/// 使用 SQLite 的 UPSERT 语法（`ON CONFLICT`）实现。
///
/// ### 参数
/// - `path`: 微信可执行文件的完整路径（例如：`C:\\Program Files\\Tencent\\WeChat\\WeChat.exe`）
///
/// ### 返回值
/// - `Ok(())`：保存成功。
/// - `Err(String)`：保存失败时返回错误信息。
///
/// ### 示例
/// ```rust
/// let path = "C:\\Program Files\\Tencent\\WeChat\\WeChat.exe";
/// save_wechat_path_to_db(path).await.expect("保存路径失败");
/// ```
#[tauri::command]
pub async fn save_wechat_path_to_db(path: &str) -> Result<(), String> {
    let pool = get_pool().await;

    sqlx::query(
        r#"
        INSERT INTO vxPath (id, path) VALUES (1, ?)
        ON CONFLICT(id) DO UPDATE SET path=excluded.path
        "#,
    )
        .bind(path)
        .execute(&pool)
        .await
        .map_err(|e| format!("保存或更新路径失败: {}", e))?;

    Ok(())
}
